Engine.Matrix4x4 = function(data){
    if(data)
	{
    	this.m00 = data[0];
    	this.m01 = data[1];
    	this.m02 = data[2];
    	this.m03 = data[3];
    	this.m10 = data[4];
    	this.m11 = data[5];
    	this.m12 = data[6];
    	this.m13 = data[7];
    	this.m20 = data[8];
    	this.m21 = data[9];
    	this.m22 = data[10];
    	this.m23 = data[11];
    	this.m30 = data[12];
    	this.m31 = data[13];
    	this.m32 = data[14];
    	this.m33 = data[15];
	}
	else
	{
		this.m00 = 0;
    	this.m01 = 0;
    	this.m02 = 0;
    	this.m03 = 0;
    	this.m10 = 0;
    	this.m11 = 0;
    	this.m12 = 0;
    	this.m13 = 0;
    	this.m20 = 0;
    	this.m21 = 0;
    	this.m22 = 0;
    	this.m23 = 0;
    	this.m30 = 0;
    	this.m31 = 0;
    	this.m32 = 0;
    	this.m33 = 0;
	}
}

Engine.Matrix4x4.prototype = (function(){
    return {
        clone : function()
        {
        	var result = new Engine.Matrix4x4();
        	result.m00 = this.m00;
        	result.m01 = this.m01;
        	result.m02 = this.m02;
        	result.m03 = this.m03;
        	result.m10 = this.m10;
        	result.m11 = this.m11;
        	result.m12 = this.m12;
        	result.m13 = this.m13;
        	result.m20 = this.m20;
        	result.m21 = this.m21;
        	result.m22 = this.m22;
        	result.m23 = this.m23;
        	result.m30 = this.m30;
        	result.m31 = this.m31;
        	result.m32 = this.m32;
        	result.m33 = this.m33;
        	return result;
        },
        
        multiply : function (m){

        	var result = new Engine.Matrix4x4();
            result.m00 = this.m00*m.m00 + this.m01*m.m10 + this.m02*m.m20 + this.m03*m.m30;
            result.m01 = this.m00*m.m01 + this.m01*m.m11 + this.m02*m.m21 + this.m03*m.m31;
            result.m02 = this.m00*m.m02 + this.m01*m.m12 + this.m02*m.m22 + this.m03*m.m32;
            result.m03 = this.m00*m.m03 + this.m01*m.m13 + this.m02*m.m23 + this.m03*m.m33;

        	result.m10 = this.m10*m.m00 + this.m11*m.m10 + this.m12*m.m20 + this.m13*m.m30;
        	result.m11 = this.m10*m.m01 + this.m11*m.m11 + this.m12*m.m21 + this.m13*m.m31;
        	result.m12 = this.m10*m.m02 + this.m11*m.m12 + this.m12*m.m22 + this.m13*m.m32;
        	result.m13 = this.m10*m.m03 + this.m11*m.m13 + this.m12*m.m23 + this.m13*m.m33;

        	result.m20 = this.m20*m.m00 + this.m21*m.m10 + this.m22*m.m20 + this.m23*m.m30;
        	result.m21 = this.m20*m.m01 + this.m21*m.m11 + this.m22*m.m21 + this.m23*m.m31;
        	result.m22 = this.m20*m.m02 + this.m21*m.m12 + this.m22*m.m22 + this.m23*m.m32;
        	result.m23 = this.m20*m.m03 + this.m21*m.m13 + this.m22*m.m23 + this.m23*m.m33;
            	
            result.m30 = this.m30*m.m00 + this.m31*m.m10 + this.m32*m.m20 + this.m33*m.m30;
        	result.m31 = this.m30*m.m01 + this.m31*m.m11 + this.m32*m.m21 + this.m33*m.m31;
        	result.m32 = this.m30*m.m02 + this.m31*m.m12 + this.m32*m.m22 + this.m33*m.m32;
        	result.m33 = this.m30*m.m03 + this.m31*m.m13 + this.m32*m.m23 + this.m33*m.m33;
            return result;
    	},
        multiplyVector : function (vector){
            if(!vector.w)
                vector.w = 1;
            return {
                x : this.m00 * vector.x + this.m01 * vector.y +this.m02 * vector.z+this.m03 * vector.w,
            	y : this.m10 * vector.x + this.m11 * vector.y +this.m12 * vector.z+this.m13 * vector.w,
            	z : this.m20 * vector.x + this.m21 * vector.y +this.m22 * vector.z+this.m23 * vector.w,
            	w : this.m30 * vector.x + this.m31 * vector.y +this.m32 * vector.z+this.m33 * vector.w
            };
        },
        determinant : function() {
            var value =
            this.m03 * this.m12 * this.m21 * this.m30 - this.m02 * this.m13 * this.m21 * this.m30 - this.m03 * this.m11 * this.m22 * this.m30 + this.m01 * this.m13 * this.m22 * this.m30 +
            this.m02 * this.m11 * this.m23 * this.m30 - this.m01 * this.m12 * this.m23 * this.m30 - this.m03 * this.m12 * this.m20 * this.m31 + this.m02 * this.m13 * this.m20 * this.m31 +
            this.m03 * this.m10 * this.m22 * this.m31 - this.m00 * this.m13 * this.m22 * this.m31 - this.m02 * this.m10 * this.m23 * this.m31 + this.m00 * this.m12 * this.m23 * this.m31 +
            this.m03 * this.m11 * this.m20 * this.m32 - this.m01 * this.m13 * this.m20 * this.m32 - this.m03 * this.m10 * this.m21 * this.m32 + this.m00 * this.m13 * this.m21 * this.m32 +
            this.m01 * this.m10 * this.m23 * this.m32 - this.m00 * this.m11 * this.m23 * this.m32 - this.m02 * this.m11 * this.m20 * this.m33 + this.m01 * this.m12 * this.m20 * this.m33 +
            this.m02 * this.m10 * this.m21 * this.m33 - this.m00 * this.m12 * this.m21 * this.m33 - this.m01 * this.m10 * this.m22 * this.m33 + this.m00 * this.m11 * this.m22 * this.m33;
            return value;
        }
    };
})();
